home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
nethack.lha
/
nethack-3.1
/
src
/
pickup.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-18
|
27KB
|
954 lines
/* SCCS Id: @(#)pickup.c 3.1 93/01/04 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
/*
* Contains code for picking objects up, and container use.
*/
#include "hack.h"
static void FDECL(unsplitobj, (struct obj *,struct obj *,long));
static void FDECL(simple_look, (struct obj *,BOOLEAN_P));
static boolean FDECL(query_classes, (char *,boolean *,boolean *,
const char *,struct obj *,BOOLEAN_P,BOOLEAN_P));
static boolean FDECL(pickup_object, (struct obj *,struct obj *));
static boolean FDECL(mbag_explodes, (struct obj *,int));
STATIC_PTR int FDECL(in_container,(struct obj *));
STATIC_PTR int FDECL(ck_bag,(struct obj *));
STATIC_PTR int FDECL(out_container,(struct obj *));
/*
* How much the weight of the given container will change when the given
* object is removed from it. This calculation must match the one used
* by weight() in mkobj.c.
*/
#define DELTA_CWT(cont,obj) \
((cont)->cursed ? (obj)->owt * 2 : \
1 + ((obj)->owt / ((cont)->blessed ? 4 : 2)))
static const char moderateloadmsg[] = "You have a little trouble lifting";
static const char nearloadmsg[] = "You have much trouble lifting";
static void
unsplitobj(obj_block, obj_chip, resplit)
register struct obj *obj_block, *obj_chip;
long resplit; /* non-zero => shift the quantities */
{
if (obj_block->nobj != obj_chip) {
impossible("can't unsplit objects");
} else if (resplit) { /* 1st object should be reduced to 'resplit' */
obj_chip->quan += (obj_block->quan - resplit);
obj_block->quan = resplit;
obj_block->owt = weight(obj_block);
obj_chip->owt = weight(obj_chip);
} else { /* 2nd obj should be merged back into 1st, then destroyed */
obj_block->nobj = obj_chip->nobj;
obj_block->nexthere = obj_chip->nexthere;
obj_block->quan += obj_chip->quan;
obj_block->owt = weight(obj_block);
/* no need to worry about 'unsplitbill'; unsplit only occurs
when unable to pick something up, hence we're not dealing
with billable objects here (I hope!)
*/
dealloc_obj(obj_chip);
}
}
/* much simpler version of the look-here code; used by query_classes() */
static void
simple_look(otmp, here)
struct obj *otmp; /* list of objects */
boolean here; /* flag for type of obj list linkage */
{
/* Neither of the first two cases is expected to happen, since
* we're only called after multiple classes of objects have been
* detected, hence multiple objects must be present.
*/
if (!otmp) {
impossible("simple_look(NULL)");
} else if (!(here ? otmp->nexthere : otmp->nobj)) {
pline("%s", doname(otmp));
} else {
winid tmpwin = create_nhwindow(NHW_MENU);
putstr(tmpwin, 0, "");
do {
putstr(tmpwin, 0, doname(otmp));
otmp = here ? otmp->nexthere : otmp->nobj;
} while (otmp);
display_nhwindow(tmpwin, TRUE);
destroy_nhwindow(tmpwin);
}
}
int
collect_obj_classes(ilets, otmp, here, incl_gold)
char ilets[];
register struct obj *otmp;
boolean here, incl_gold;
{
register int iletct = 0;
register char c, last_c = '\0';
if (incl_gold)
ilets[iletct++] = def_oc_syms[GOLD_CLASS];
ilets[iletct] = '\0'; /* terminate ilets so that index() will work */
while (otmp) {
c = def_oc_syms[(int)otmp->oclass];
if (c != last_c && !index(ilets, (last_c = c)))
ilets[iletct++] = c, ilets[iletct] = '\0';
otmp = here ? otmp->nexthere : otmp->nobj;
}
return iletct;
}
static boolean
query_classes(olets, one_at_a_time, everything, action, objs, here, incl_gold)
char olets[];
boolean *one_at_a_time, *everything;
const char *action;
struct obj *objs;
boolean here, incl_gold;
{
char ilets[20], inbuf[BUFSZ];
int iletct, oletct;
char qbuf[QBUFSZ];
olets[oletct = 0] = '\0';
*one_at_a_time = *everything = FALSE;
iletct = collect_obj_classes(ilets, objs, here, incl_gold);
if (iletct == 0) {
return FALSE;
} else if (iletct == 1) {
olets[0] = def_char_to_objclass(ilets[0]);
olets[1] = '\0';
} else { /* more than one choice available */
const char *where = 0;
register char sym, oc_of_sym, *p;
/* additional choices */
ilets[iletct++] = ' ';
ilets[iletct++] = 'a';
ilets[iletct++] = 'A';
ilets[iletct++] = (objs == invent ? 'i' : ':');
ilets[iletct] = '\0';
ask_again:
olets[oletct = 0] = '\0';
*one_at_a_time = *everything = FALSE;
Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
action, ilets);
getlin(qbuf,inbuf);
if (*inbuf == '\033') {
clear_nhwindow(WIN_MESSAGE);
return FALSE;
}
for (p = inbuf; (sym = *p++); ) {
/* new A function (selective all) added by GAN 01/09/87 */
if (sym == ' ') continue;
else if (sym == 'A') *one_at_a_time = TRUE;
else if (sym == 'a') *everything = TRUE;
else if (sym == ':') {
simple_look(objs, here); /* dumb if objs==invent */
goto ask_again;
} else if (sym == 'i') {
(void) display_inventory(NULL, FALSE);
goto ask_again;
} else {
oc_of_sym = def_char_to_objclass(sym);
if (index(ilets,sym)) {
olets[oletct++] = oc_of_sym;
olets[oletct] = '\0';
} else {
if (!where)
where = !strcmp(action,"pick up") ? "here" :
!strcmp(action,"take out") ?
"inside" : "";
if (*where)
pline("There are no %c's %s.", sym, where);
else
You("have no %c's.", sym);
}
}
}
if (!oletct && !*everything) *one_at_a_time = TRUE;
}
return TRUE;
}
void
pickup(all)
int all; /* all >= 0 => yes/no; < 0 => -count */
{
register struct obj *obj;
struct obj *obj2, *objx;
boolean all_of_a_type = FALSE, selective = FALSE;
char olets[20];
long count;
count = (all < 0) ? (-1L * all) : 0L;
if (count) all = 0;
if(Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
if ((multi && !flags.run) || (all && !flags.pickup))
read_engr_at(u.ux,u.uy);
return;
}
/* multi && !flags.run means they are in the middle of some other
* action, or possibly paralyzed, sleeping, etc.... and they just
* teleported onto the object. They shouldn't pick it up.
*/
if ((multi && !flags.run) || (all && !flags.pickup)) {
int ct = 0;
for (obj = level.objects[u.ux][u.uy]; obj;
obj = obj->nexthere)
if(obj != uchain)
ct++;
/* If there are objects here, take a look.
*/
if (ct) {
if (flags.run)
nomul(0);
flush_screen(1);
if (ct < 5)
(void) dolook();
else {
read_engr_at(u.ux,u.uy);
pline("There are several objects here.");
}
} else read_engr_at(u.ux,u.uy);
return;
}
/* check for more than one object */
if(!all) {
register int ct = 0;
for(obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
ct++;
if(ct < 2)
all++;
else {
pline("There are several objects here.");
count = 0;
}
}
#ifdef POLYSELF
if (nolimbs(uasmon)) {
You("cannot pick things up without limbs.");
return;
}
#endif
/* added by GAN 10/24/86 to allow selective picking up */
if (!all) {
if (!query_classes(olets, &selective, &all_of_a_type,
"pick up", level.objects[u.ux][u.uy], TRUE, FALSE))
return;
}
if(all_of_a_type && !olets[0]) all = TRUE;
for(obj = level.objects[u.ux][u.uy]; obj; obj = obj2) {
obj2 = obj->nexthere; /* perhaps obj will be picked up */
objx = 0;
if(flags.run) nomul(0);
if(!all) {
if(!selective && !index(olets,obj->oclass)) continue;
if (!all_of_a_type) {
char qbuf[QBUFSZ];
Sprintf(qbuf,"Pick up %s?", doname(obj));
switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) {
case 'q': return;
case 'n': continue;
case 'a':
all_of_a_type = TRUE;
if (selective) {
selective = FALSE;
olets[0] = obj->oclass;
olets[1] = '\0';
}
break;
case '#': /* count was entered */
if (!yn_number) continue; /* 0 count => No */
else count = yn_number;
/* fall thru :-} */
default: /* 'y' */
break;
}
}
}
if (count) {
/* Pickup a specific number of items; split the object
unless count corresponds to full quantity. 1 special
case: cursed loadstones will remain as merged unit.
*/
if (count < obj->quan &&
(!obj->cursed || obj->otyp != LOADSTONE)) {
objx = splitobj(obj, count);
if (!objx || objx->nexthere != obj2)
impossible("bad object split in pickup");
}
count = 0; /* reset */
}
if (pickup_object(obj, objx)) break;
}
/*
* Re-map what is at the hero's location after the pickup so the
* map is correct.
*/
newsym(u.ux,u.uy);
}
/*
* Pick up an object from the ground or out of a container and add it to
* the inventory. Returns true if pickup() should break out of its loop.
*/
static boolean
pickup_object(obj, objx)
struct obj *obj, *objx;
{
int wt, nearload;
long pickquan;
if (obj == uchain) { /* do not pick up attached chain */
return FALSE;
} else if (obj->oartifact && !touch_artifact(obj,&youmonst)) {
return FALSE;
} else if (obj->otyp == GOLD_PIECE) {
/*
* Special consideration for gold pieces...
*/
long iw = (long)max_capacity() - ((u.ugold + 50L) / 100L);
long gold_capacity = ((-iw) * 100L) - 50L + 99L - u.ugold;
if (gold_capacity <= 0L) {
if (objx) unsplitobj(obj, objx, 0L);
pline("There %s %ld gold piece%s here, but you cannot carry any more.",
(obj->quan == 1L) ? "is" : "are",
obj->quan, plur(obj->quan));
return FALSE;
} else if (gold_capacity < obj->quan) {
if (objx) unsplitobj(obj, objx, 0L);
You("can only carry %s of the %ld gold pieces lying here.",
gold_capacity == 1L ? "one" : "some", obj->quan);
pline("%s %ld gold piece%s.",
nearloadmsg, gold_capacity, plur(gold_capacity));
u.ugold += gold_capacity;
obj->quan -= gold_capacity;
costly_gold(obj->ox, obj->oy, gold_capacity);
} else {
u.ugold += obj->quan;
if ((nearload = near_capacity()) != 0)
pline("%s %ld gold piece%s.",
nearload < MOD_ENCUMBER ?
moderateloadmsg : nearloadmsg,
obj->quan, plur(obj->quan));
else
prinv(NULL, obj, 0L);
costly_gold(obj->ox, obj->oy, obj->quan);
delobj(obj);
}
flags.botl = 1;
if (flags.run) nomul(0);
return FALSE;
} else if (obj->otyp == CORPSE) {
if (obj->corpsenm == PM_COCKATRICE && !uarmg
#ifdef POLYSELF
&& !resists_ston(uasmon)
#endif
) {
#ifdef POLYSELF
if (poly_when_stoned(uasmon) && polymon(PM_STONE_GOLEM))
display_nhwindow(WIN_MESSAGE, FALSE);
else
#endif
{
pline("Touching the cockatrice corpse is a fatal mistake.");
You("turn to stone.");
You("die...");
killer_format = KILLED_BY_AN;
killer = "cockatrice corpse";
done(STONING);
}
} else if (is_rider(&mons[obj->corpsenm])) {
pline("At your touch, the corpse suddenly moves...");
revive_corpse(obj, 1, FALSE);
exercise(A_WIS, FALSE);
return FALSE;
}
} else if (obj->otyp == SCR_SCARE_MONSTER) {
if (obj->blessed) obj->blessed = 0;
else if (!obj->spe && !obj->cursed) obj->spe = 1;
else {
pline("The scroll%s turn%s to dust as you pick %s up.",
plur(obj->quan), (obj->quan == 1L) ? "s" : "",
(obj->quan == 1L) ? "it" : "them");
if (!(objects[SCR_SCARE_MONSTER].oc_name_known) &&
!(objects[SCR_SCARE_MONSTER].oc_uname))
docall(obj);
useupf(obj);
return FALSE;
}
}
wt = max_capacity() + (int)obj->owt;
if (obj->otyp == LOADSTONE)
goto lift_some; /* pick it up even if too heavy */
#ifdef POLYSELF
if (obj->otyp == BOULDER && throws_rocks(uasmon)) {
goto lift_some;
}
#endif
if (wt > 0) {
if (obj->quan > 1L) {
/* see how many we can lift */
long qq, savequan = obj->quan;
int iw = max_capacity();
/* This is correct only because containers */
/* don't merge. -dean */
for (qq = 1; qq < savequan; qq++) {
obj->quan = qq;
if (iw + weight(obj) > 0)
break;
}
obj->quan = savequan;
qq--;
/* we can carry qq of them */
if (qq) {
if (objx) { /* temporarily unsplit */
savequan = obj->quan;
obj->quan += objx->quan;
}
You("can only carry %s of the %s lying here.",
(qq == 1L) ? "one" : "some", doname(obj));
if (objx) { /* re-do the prior split */
obj->quan = savequan;
unsplitobj(obj, objx, qq);
} else { /* split into two groups */
objx = splitobj(obj, qq);
if (objx->otyp == SCR_SCARE_MONSTER) objx->spe = 0;
}
goto lift_some;
}
}
if (objx) unsplitobj(obj, objx, 0L);
pline("There %s %s here, but %s.",
(obj->quan == 1L) ? "is" : "are", doname(obj),
!invent ? (obj->quan == 1L ?
"it is too heavy for you to lift" :
"they are too heavy for you to lift") :
"you cannot carry any more");
if (obj->otyp == SCR_SCARE_MONSTER) obj->spe = 0;
return TRUE;
}
lift_some:
if (inv_cnt() >= 52) {
if (objx) unsplitobj(obj, objx, 0L);
Your("knapsack cannot accommodate any more items.");
if (obj->otyp == SCR_SCARE_MONSTER) obj->spe = 0;
return TRUE;
}
pickquan = obj->quan; /* save number picked up */
obj = pick_obj(obj);
if (!Blind) obj->dknown = 1;
if (uwep && uwep == obj) mrg_to_wielded = TRUE;
nearload = near_capacity();
prinv(nearload > SLT_ENCUMBER ? nearloadmsg :
nearload > UNENCUMBERED ? moderateloadmsg : NULL,
obj, pickquan);
mrg_to_wielded = FALSE;
return FALSE;
}
/* Gold never reaches this routine. */
struct obj *
pick_obj(otmp)
register struct obj *otmp;
{
freeobj(otmp);
if (*u.ushops && costly_spot(u.ux, u.uy) &&
otmp != uball) /* don't charge for this - kd, 1/17/90 */
/* sets obj->unpaid if necessary */
addtobill(otmp, TRUE, FALSE, FALSE);
if(Invisible) newsym(u.ux,u.uy);
return(addinv(otmp)); /* might merge it with other objects */
}
/*
* prints a message if encumbrance changed since the last check and
* returns the new encumbrance value (from near_capacity()).
*/
int
encumber_msg()
{
static int oldcap = UNENCUMBERED;
int newcap = near_capacity();
if(oldcap < newcap) {
switch(newcap) {
case 1: Your("movements are slowed slightly because of your load.");
break;
case 2: You("rebalance your load. Movement is difficult.");
break;
case 3: You("stagger under your heavy load. Movement is very hard.");
break;
default: You("can barely move a handspan with this load!");
break;
}
flags.botl = 1;
} else if(oldcap > newcap) {
switch(newcap) {
case 0: Your("movements are now unencumbered.");
break;
case 1: Your("movements are only slowed slightly by your load.");
break;
case 2: You("rebalance your load. Movement is still difficult.");
break;
case 3: You("stagger under your load. Movement is still very hard.");
break;
}
flags.botl = 1;
}
oldcap = newcap;
return (newcap);
}
int
doloot() /* loot a container on the floor. */
{
register struct obj *cobj, *nobj;
register int c;
int timepassed = 0;
if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
You("cannot reach the floor.");
return(0);
}
if(is_pool(u.ux, u.uy)) {
You("cannot loot things that are deep in the water.");
return(0);
}
#ifdef POLYSELF
if(nolimbs(uasmon)) {
You("cannot loot things without limbs.");
return(0);
}
#endif
for(cobj = level.objects[u.ux][u.uy]; cobj; cobj = nobj) {
nobj = cobj->nexthere;
if(Is_container(cobj)) {
char qbuf[QBUFSZ];
Sprintf(qbuf, "There is %s here, loot it?", doname(cobj));
c = ynq(qbuf);
if(c == 'q') return (timepassed);
if(c == 'n') continue;
if(cobj->olocked) {
pline("Hmmm, it seems to be locked.");
continue;
}
if(cobj->otyp == BAG_OF_TRICKS) {
You("carefully open the bag...");
pline("It develops a huge set of teeth and bites you!");
c = rnd(10);
if(Half_physical_damage) c = (c+1) / 2;
losehp(c, "carnivorous bag", KILLED_BY_AN);
makeknown(BAG_OF_TRICKS);
timepassed = 1;
continue;
}
You("carefully open %s...", the(xname(cobj)));
if (cobj->otrapped && chest_trap(cobj, FINGER, FALSE)) {
timepassed = 1;
continue; /* explosion destroyed cobj */
}
if(multi < 0) return (1); /* a paralysis trap */
timepassed |= use_container(cobj, 0);
}
}
return (timepassed);
}
/*
* Decide whether an object being placed into a magic bag will cause
* it to explode. If the object is a bag itself, check recursively.
*/
static boolean
mbag_explodes(obj, depthin)
struct obj *obj;
int depthin;
{
/* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */
if ((Is_mbag(obj) || (obj->otyp == WAN_CANCELLATION && obj->spe > 0)) &&
(rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin))
return TRUE;
else if (Is_container(obj)) {
struct obj *otmp;
for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
if (mbag_explodes(otmp, depthin+1)) return TRUE;
}
return FALSE;
}
/* A variable set in use_container(), to be used by the callback routines */
/* chk_bg(), in_container(), and out_container() from askchain(). */
static struct obj NEARDATA *current_container;
#define Icebox (current_container->otyp == ICE_BOX)
STATIC_PTR int
in_container(obj)
register struct obj *obj;
{
register struct obj *gold;
boolean is_gold = (obj->otyp == GOLD_PIECE);
boolean floor_container = !carried(current_container);
char buf[BUFSZ];
if (!current_container) {
impossible("<in> no current_container?");
return 0;
} else if (obj == uball || obj == uchain) {
You("must be kidding.");
return 0;
} else if (obj == current_container) {
pline("That would be an interesting topological exercise.");
return 0;
} else if (obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) {
Norep("You cannot %s something you are wearing.",
Icebox ? "refrigerate" : "stash");
return 0;
} else if ((obj->otyp == LOADSTONE) && obj->cursed) {
obj->bknown = 1;
pline("The stone%s won't leave your person.", plur(obj->quan));
return 0;
} else if (obj->otyp == AMULET_OF_YENDOR ||
obj->otyp == CANDELABRUM_OF_INVOCATION ||
obj->otyp == BELL_OF_OPENING ||
obj->otyp == SPE_BOOK_OF_THE_DEAD) {
/* Prohibit Amulets in containers; if you allow it, monsters can't
* steal them. It also becomes a pain to check to see if someone
* has the Amulet. Ditto for the Candelabrum, the Bell and the Book.
*/
pline("%s cannot be confined in such trappings.", The(xname(obj)));
return 0;
}
#ifdef WALKIES
else if (obj->otyp == LEASH && obj->leashmon != 0) {
pline("%s is attached to your pet.", The(xname(obj)));
return 0;
}
#endif
else if (obj == uwep) {
if (welded(obj)) {
weldmsg(obj, FALSE);
return 0;
}
setuwep((struct obj *) 0);
if (uwep) return 0; /* unwielded, died, rewielded */
}
/* boxes can't fit into any container */
if (obj->otyp == ICE_BOX || Is_box(obj)) {
/*
* xname() uses a static result array. Save obj's name
* before current_container's name is computed. Don't
* use the result of strcpy() within You() --- the order
* of evaluation of the parameters is undefined.
*/
Strcpy(buf, the(xname(obj)));
You("cannot fit %s into %s.", buf,
the(xname(current_container)));
return 0;
}
freeinv(obj);
if (is_gold) { /* look for other gold within the container */
for (gold = current_container->cobj; gold; gold = gold->nobj)
if (gold->otyp == GOLD_PIECE) break;
} else
gold = 0;
if (gold) {
gold->quan += obj->quan;
} else {
obj->nobj = current_container->cobj;
current_container->cobj = obj;
}
current_container->owt = weight(current_container);
Strcpy(buf, the(xname(current_container)));
You("put %s into %s.", doname(obj), buf);
if (floor_container && costly_spot(u.ux, u.uy)) {
sellobj_state(TRUE);
sellobj(obj, u.ux, u.uy);
sellobj_state(FALSE);
}
(void) snuff_candle(obj); /* must follow the "put" msg */
if (Icebox && obj->otyp != OIL_LAMP && obj->otyp != BRASS_LANTERN
&& !Is_candle(obj))
obj->age = monstermoves - obj->age; /* actual age */
else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) {
You("are blasted by a magical explosion!");
/* the !floor_container case is taken care of */
if(*u.ushops && costly_spot(u.ux, u.uy) && floor_container) {
register struct monst *shkp;
if ((shkp = shop_keeper(*u.ushops)) != 0)
(void)stolen_value(current_container, u.ux, u.uy,
(boolean)shkp->mpeaceful, FALSE);
}
delete_contents(current_container);
if (!floor_container)
useup(current_container);
else if (obj_here(current_container, u.ux, u.uy))
useupf(current_container);
else
panic("in_container: bag not found.");
losehp(d(6,6),"magical explosion", KILLED_BY_AN);
current_container = 0; /* baggone = TRUE; */
}
if (is_gold) {
if (gold) dealloc_obj(obj);
bot(); /* update character's gold piece count immediately */
}
return(current_container ? 1 : -1);
}
STATIC_PTR int
ck_bag(obj)
struct obj *obj;
{
return current_container && obj != current_container;
}
STATIC_PTR int
out_container(obj)
register struct obj *obj;
{
register struct obj *otmp, *ootmp;
boolean is_gold = (obj->otyp == GOLD_PIECE);
int loadlev;
long quan;
if (!current_container) {
impossible("<out> no current_container?");
return -1;
} else if (is_gold) {
obj->owt = weight(obj);
} else if (inv_cnt() >= 52) {
You("have no room to hold anything else.");
return -1; /* skips gold too; oh well */
}
if(obj->oartifact && !touch_artifact(obj,&youmonst)) return 0;
if(obj->otyp != LOADSTONE && max_capacity() + (int)obj->owt -
(carried(current_container) ?
(current_container->otyp == BAG_OF_HOLDING ?
(int)DELTA_CWT(current_container,obj) : (int)obj->owt) : 0) > 0) {
char buf[BUFSZ];
Strcpy(buf, doname(obj));
pline("There %s %s in %s, but %s.",
obj->quan==1 ? "is" : "are",
buf, the(xname(current_container)),
invent ? "you cannot carry any more"
: "it is too heavy for you to carry");
/* "too heavy for you to lift" is not right if you're carrying
the container... */
return(0);
}
/* Remove the object from the list. */
if (obj == current_container->cobj)
current_container->cobj = obj->nobj;
else {
for(otmp = current_container->cobj; otmp->nobj != obj;
otmp = otmp->nobj)
if(!otmp->nobj) panic("out_container");
otmp->nobj = obj->nobj;
}
current_container->owt = weight(current_container);
if (Icebox && obj->otyp != OIL_LAMP && obj->otyp != BRASS_LANTERN
&& !Is_candle(obj))
obj->age = monstermoves - obj->age;
/* simulated point of time */
if(!obj->unpaid && !carried(current_container) &&
costly_spot(current_container->ox, current_container->oy)) {
addtobill(obj, FALSE, FALSE, FALSE);
}
quan = obj->quan;
ootmp = addinv(obj);
loadlev = near_capacity();
prinv(loadlev ?
(loadlev < MOD_ENCUMBER ?
"You have a little trouble removing" :
"You have much trouble removing") : NULL,
ootmp, quan);
if (is_gold) {
dealloc_obj(obj);
bot(); /* update character's gold piece count immediately */
}
return 1;
}
/* for getobj: allow counts, allow all types, expect food */
static const char NEARDATA frozen_food[] =
{ ALLOW_COUNT, ALL_CLASSES, FOOD_CLASS, 0 };
int
use_container(obj, held)
register struct obj *obj;
register int held;
{
register int cnt = 0;
register struct obj *curr, *prev, *otmp;
boolean one_by_one, allflag;
char select[MAXOCLASSES+1];
char qbuf[QBUFSZ];
int used = 0, lcnt = 0;
long loss = 0L;
register struct monst *shkp;
current_container = obj; /* for use by in/out_container */
if (current_container->olocked) {
pline("%s seems to be locked.", The(xname(current_container)));
if (held) You("must put it down to unlock.");
return 0;
}
/* Count the number of contained objects. Sometimes toss objects if */
/* a cursed magic bag. */
for(curr = obj->cobj, prev = (struct obj *) 0; curr;
prev = curr, curr = otmp) {
otmp = curr->nobj;
if (Is_mbag(obj) && obj->cursed && !rn2(13)) {
if (curr->known)
pline("%s to have vanished!", The(aobjnam(curr,"seem")));
else
You("%s %s disappear.", Blind ? "notice" : "see",
doname(curr));
if (prev)
prev->nobj = otmp;
else
obj->cobj = otmp;
if(*u.ushops && (shkp = shop_keeper(*u.ushops))) {
if(held) {
if(curr->unpaid)
loss += stolen_value(curr, u.ux, u.uy,
(boolean)shkp->mpeaceful, TRUE);
lcnt++;
} else if(costly_spot(u.ux, u.uy)) {
loss += stolen_value(curr, u.ux, u.uy,
(boolean)shkp->mpeaceful, TRUE);
lcnt++;
}
}
/* obfree() will free all contained objects */
obfree(curr, (struct obj *) 0);
} else
cnt++;
}
if (cnt && loss)
You("owe %ld zorkmids for lost item%s.",
loss, lcnt > 1 ? "s" : "");
current_container->owt = weight(current_container);
if(!cnt)
pline("%s %s is empty.", (held) ? "Your" : "The", xname(obj));
else {
Sprintf(qbuf, "Do you want to take something out of %s?",
the(xname(obj)));
ask_again:
switch (yn_function(qbuf, ":ynq", 'n')) {
case ':':
container_contents(current_container, FALSE, FALSE);
goto ask_again;
case 'y':
if (query_classes(select, &one_by_one, &allflag, "take out",
current_container->cobj, FALSE, FALSE)) {
if (askchain((struct obj **)¤t_container->cobj,
(one_by_one ? (char *)0 : select), allflag,
out_container, (int (*)())0, 0, "nodot"))
used = 1;
}
/*FALLTHRU*/
case 'n':
break;
case 'q':
default:
return 0;
}
}
if (!invent && (u.ugold == 0 || Icebox)) return used;
if (yn_function("Do you wish to put something in?", ynqchars, 'n')
!= 'y') return used;
if (Icebox && current_container->dknown) {
otmp = getobj(frozen_food, "put in");
if(!otmp || !in_container(otmp))
flags.move = multi = 0;
} else {
if (query_classes(select, &one_by_one, &allflag, "put in",
invent, FALSE, (u.ugold != 0L))) {
struct obj *u_gold = (struct obj *)0;
if (u.ugold && (one_by_one || (allflag && !*select)
|| index(select, GOLD_CLASS))) {
/* make gold object & insert at head of inventory */
u_gold = mkgoldobj(u.ugold); /*(removes gold too)*/
u.ugold = u_gold->quan; /* put the gold back */
u_gold->nobj = invent;
invent = u_gold;
}
used = (askchain((struct obj **)&invent,
(one_by_one ? (char *)0 : select), allflag,
in_container, ck_bag, 0, "nodot") > 0);
if (u_gold && invent && invent->otyp == GOLD_PIECE) {
/* didn't stash [all of] it */
u_gold = invent;
invent = u_gold->nobj;
dealloc_obj(u_gold);
}
}
}
return used;
}
/*pickup.c*/